package xcmg.device.service.delivery;

import com.github.pagehelper.PageInfo;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.delivery.DeliveryNoteDO;
import xcmg.device.dao.entity.delivery.DeliveryNoteDetailDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptDO;
import xcmg.device.dao.entity.delivery.DeliveryReceiptLinkDO;
import xcmg.device.dao.entity.delivery.ReceiptInDO;
import xcmg.device.dao.entity.delivery.ReceiptInDetailDO;
import xcmg.device.dao.entity.purchase.PurchaseRequestDO;
import xcmg.device.dao.entity.purchase.PurchaseRequestDetailDO;
import xcmg.device.dao.entity.sale.SaleIntentionDO;
import xcmg.device.dao.entity.warehouse.WarehouseDO;
import xcmg.device.dao.entity.warehouse.WarehouseDeliveryRecordDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundRecordDO;
import xcmg.device.dao.mapper.BoxupDetailMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.MaterialLocationRelationMapper;
import xcmg.device.dao.mapper.PurchaseRequestDetailMapper;
import xcmg.device.dao.mapper.PurchaseRequestMapper;
import xcmg.device.dao.mapper.SaleIntentionMapper;
import xcmg.device.dao.mapper.delivery.DeliveryNoteDetailMapper;
import xcmg.device.dao.mapper.delivery.DeliveryNoteMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptLinkMapper;
import xcmg.device.dao.mapper.delivery.DeliveryReceiptMapper;
import xcmg.device.dao.mapper.delivery.ReceiptInDetailMapper;
import xcmg.device.dao.mapper.delivery.ReceiptInMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDeliveryRecordMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundRecordMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.infra.CalcUtil;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.vo.basic.MaterialLocationRelationVO;
import xcmg.device.service.vo.boxup.BoxupMaterialsQuery;
import xcmg.device.service.vo.delivery.ReceiptInAddVO;
import xcmg.device.service.vo.delivery.ReceiptInDetailVO;
import xcmg.device.service.vo.delivery.ReceiptInVO;
import xcmg.device.service.vo.warehouse.WarehouseDeliveryRecordVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordVO;
import xcmg.device.service.warehouse.CommonService;
import xcmg.device.service.warehouse.WarehouseInboundService;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ReceiptInService {

    @Autowired
    private ReceiptInMapper receiptInMapper;

    @Autowired
    private ReceiptInDetailMapper receiptInDetailMapper;

    @Autowired
    private WarehouseDOMapper warehouseDOMapper;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private CompanyInfoMapper companyInfoMapper;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private WarehouseInboundService warehouseInboundService;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;

    @Autowired
    private DeliveryReceiptMapper deliveryReceiptMapper;

    @Autowired
    private DeliveryReceiptLinkMapper deliveryReceiptLinkMapper;

    @Autowired
    private WarehouseDeliveryRecordMapper warehouseDeliveryRecordMapper;

    @Autowired
    private DeliveryNoteMapper deliveryNoteMapper;
    @Autowired
    private DeliveryNoteDetailMapper deliveryNoteDetailMapper;

    @Autowired
    private SaleIntentionMapper saleIntentionMapper;

    @Autowired
    private PurchaseRequestMapper purchaseRequestMapper;

    @Autowired
    private PurchaseRequestDetailMapper purchaseRequestDetailMapper;

    @Autowired
    private DeliveryReceiptMaterialService deliveryReceiptMaterialService;
    @Autowired
    private BoxupDetailMapper boxupDetailMapper;
    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;
    @Autowired
    private MaterialLocationRelationMapper materialLocationRelationMapper;
    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;

    @Autowired
    private WarehouseInboundRecordMapper warehouseInboundRecordMapper;

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(ReceiptInAddVO receiptInAddVO, String userId, String orgId) throws Exception {
        if (receiptInAddVO.getHeaderInfo() == null || ListUtil.isNullOrEmpty(receiptInAddVO.getDetailList())) {
            return ErrorCode.IllegalArument;
        }
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }

        CompanyInfoDO infoDO = companyInfoMapper.item(receiptInAddVO.getHeaderInfo().getSupplierOrgId());
        if (infoDO == null) {
            return ErrorCode.IllegalArument;
        }

        ReceiptInDO receiptInDO = new ReceiptInDO();
        BeanUtils.copyProperties(receiptInAddVO.getHeaderInfo(), receiptInDO);
        receiptInDO.setId(textResult.getValue());
        receiptInDO.setBillNo(genDocumentService.getDocumentNo(BillDesc.ReceiptIn));
        receiptInDO.setOrgId(orgId);
        receiptInDO.setCreateId(userId);
        receiptInDO.setCreateName(commonService.getUserName(userId));
        receiptInDO.setCreateDate(new Date());
        receiptInDO.setSupplierOrgName(infoDO.getCompanyName());
        boolean success = receiptInMapper.insert(receiptInDO) > 0;
        if (!success) {
            throw new Exception("操作失败");
        }

        for (ReceiptInDetailVO detialVO : receiptInAddVO.getDetailList()) {
            ReceiptInDetailDO detialDO = new ReceiptInDetailDO();
            BeanUtils.copyProperties(detialVO, detialDO);
            detialDO.setMainId(receiptInDO.getId());
            detialDO.setId(fastGenClient.textGuid().getValue());
            success = receiptInDetailMapper.insert(detialDO) > 0;
            if (!success) {
                throw new Exception("操作失败");
            }

            //如果是由发运交接单生成，更新发运交接单状态
            if (!StringUtil.isNullOrEmpty(receiptInAddVO.getHeaderInfo().getReceiptId())) {
                deliveryReceiptMaterialService.updateSendStatus(receiptInAddVO.getHeaderInfo().getReceiptId(), receiptInDO.getReceiptNo(), detialDO.getMaterialsNo(), detialDO.getAmount());
            }
        }

        BeanUtils.copyProperties(receiptInDO, receiptInAddVO.getHeaderInfo());
        success = warehouseInboundService.saveByReceiptIn(receiptInAddVO, userId, orgId, receiptInAddVO.getHeaderInfo().getSupplierOrgId());
        if (!success) {
            throw new Exception("生成入库事物单失败");
        }
        return ErrorCode.Success;
    }

    public PageCommonVO list(SearchCommonVO<ReceiptInVO> condition) {
        PageCommonVO<ReceiptInVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        List<ReceiptInDO> doList = receiptInMapper.list(condition.getFilters());
        List<ReceiptInVO> voList = new ArrayList<>();
        for (ReceiptInDO entity : doList) {
            ReceiptInVO model = new ReceiptInVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    public ReceiptInAddVO item(String id, String orgId) throws Exception {
        ReceiptInAddVO result = new ReceiptInAddVO();
        ReceiptInDO receiptInDO = receiptInMapper.selectByPrimaryKey(id);
        if (receiptInDO == null) {
            return result;
        }
        ReceiptInVO receiptInVO = new ReceiptInVO();
        BeanUtils.copyProperties(receiptInDO, receiptInVO);
        if (StringUtils.isNotBlank(receiptInVO.getWarehouseCode())) {
            WarehouseDO warehouse = warehouseDOMapper.itemByWarehouseCode(orgId, receiptInVO.getWarehouseCode());
            if (null != warehouse) {
                receiptInVO.setWarehouseCodeDesc(warehouse.getDescription());
                receiptInVO.setIsBarCode(warehouse.getIsBarCode());
            }
        }
        result.setHeaderInfo(receiptInVO);

        //根据是否条码化仓库查询零件条码
        if (null == receiptInVO.getIsBarCode()) {
            throw new Exception("调入仓库不能为空");
        }

        List<ReceiptInDetailDO> listDO = receiptInDetailMapper.listByMainId(id);
        Map<String, ReceiptInDetailDO> detailDOMap = listDO.stream().collect(Collectors.toMap(ReceiptInDetailDO::getMaterialsNo, Function.identity(), (k1, k2) -> k2));

        List<String> materialsNos = listDO.stream().map(ReceiptInDetailDO::getMaterialsNo).distinct().collect(Collectors.toList());
        List<ReceiptInDetailVO> listVO = new ArrayList<>();
        if (receiptInVO.getIsBarCode() == 1) {//条码化
            //根据运单id查询关联发货通知单号
            String receiptNo = receiptInVO.getReceiptNo();
            List<String> deliveryNoteNoList = deliveryReceiptLinkMapper.findByDeliveryBillNo(receiptNo);
            if (CollectionUtils.isNotEmpty(deliveryNoteNoList)) {
                WarehouseDeliveryRecordVO recordVO = new WarehouseDeliveryRecordVO();
                recordVO.setBusinessOrderList(deliveryNoteNoList);
                List<WarehouseDeliveryRecordDO> recordDOList = warehouseDeliveryRecordMapper.list(recordVO);
                if (!CollectionUtils.isEmpty(recordDOList)) {

                    //合并出库记录
                    Map<String, WarehouseDeliveryRecordDO> recordDOMap = recordDOList.stream().collect(
                            Collectors.toMap(WarehouseDeliveryRecordDO::getBarCode, Function.identity(), (k1, k2) -> {
                                k1.setAmount(k1.getAmount().add(k2.getAmount()));
                                return k1;
                            })
                    );
                    List<WarehouseDeliveryRecordDO> mergeList = recordDOMap.values().stream().collect(Collectors.toList());

                    //TODO: 2021/4/9 回写状态时根据发运交接单数量判断--（数量匹配上就入库修改状态-不精确）
                    //查询入库记录
                    Map<String, WarehouseInboundRecordDO> inboundRecordDOMap = new HashMap<>();
                    List<String> barcodeList = mergeList.stream().map(WarehouseDeliveryRecordDO::getBarCode).distinct().collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(barcodeList)) {
                        WarehouseInboundRecordVO inboundRecordVO = new WarehouseInboundRecordVO();
                        inboundRecordVO.setOrgId(orgId);
                        inboundRecordVO.setBarcodeList(barcodeList);
                        List<WarehouseInboundRecordDO> inboundRecordDOList = warehouseInboundRecordMapper.list(inboundRecordVO);
                        if (CollectionUtils.isNotEmpty(inboundRecordDOList)) {
                            inboundRecordDOMap = inboundRecordDOList.stream().collect(Collectors.toMap(WarehouseInboundRecordDO::getBarCode, Function.identity(), (k1, k2) -> k2));
                        }
                    }

                    ReceiptInDetailVO model;
                    //出入库记录
                    for (WarehouseDeliveryRecordDO recordDO : mergeList) {
                        String materialNo = recordDO.getMaterialNo();
                        if (materialsNos.contains(materialNo)) {
                            model = new ReceiptInDetailVO();
                            BeanUtils.copyProperties(recordDO, model);
                            //赋值入库单id
                            if (detailDOMap.containsKey(materialNo)) {
                                model.setId(detailDOMap.get(materialNo).getId());
                                model.setNote(detailDOMap.get(materialNo).getNote());//备注
                            }
                            model.setLocationCode(null);//先置空
                            model.setMaterialsNo(materialNo);
                            model.setMaterialsDes(recordDO.getMaterialName());
                            model.setMaterialsType(recordDO.getMaterialType());
                            if (inboundRecordDOMap.containsKey(recordDO.getBarCode())) {
                                WarehouseInboundRecordDO inboundRecordDO = inboundRecordDOMap.get(recordDO.getBarCode());
                                if (inboundRecordDO.getAmount().compareTo(recordDO.getAmount()) == 0) {
                                    model.setStatus(2);//已入库
                                } else {
                                    model.setStatus(1);//部分入库
                                }
                                model.setRealAmount(inboundRecordDO.getAmount());
                            }
                            processLocationCodeAndPrice(receiptInDO, model, orgId);
                            listVO.add(model);
                        }
                    }
                }
            }
        } else {//非条码
            for (ReceiptInDetailDO entity : listDO) {
                ReceiptInDetailVO model = new ReceiptInDetailVO();
                BeanUtils.copyProperties(entity, model);
                processLocationCodeAndPrice(receiptInDO, model, orgId);
                listVO.add(model);
            }

        }
        result.setDetailList(listVO);
        return result;
    }

    /**
     * 处理储位和价格
     *
     * @param receiptInDO
     * @param model
     * @param orgId
     */
    private void processLocationCodeAndPrice(ReceiptInDO receiptInDO, ReceiptInDetailVO model, String orgId) throws Exception {
        model.setPrintPrice(this.getPrice(receiptInDO.getBillNo(), model.getMaterialsNo()));
        //获取库存储位
        String stockLocationCode = warehouseInventoryMapper.findInventoryLocationCode(model.getMaterialsNo(),
                receiptInDO.getWarehouseCode(), orgId, receiptInDO.getAreaCode());
        if (StringUtils.isEmpty(stockLocationCode)) {
            // 获取默认储位
            getDefaultLocationCode(orgId, receiptInDO.getWarehouseCode(), model);
        } else {
            model.setLocationCode(stockLocationCode);
        }

        String locationCode = model.getLocationCode();
        if (StringUtils.isNotBlank(locationCode)) {
            model.setLocationDesc(warehouseAreaLocationDOMapper.getLocationDesc(locationCode));
        }
    }

    // 获取默认储位
    private void getDefaultLocationCode(String orgId, String warehouseCode, ReceiptInDetailVO detailVO) {
        MaterialLocationRelationVO condition = new MaterialLocationRelationVO();
        condition.setWarehouseCode(warehouseCode);
        condition.setOrgId(orgId);
        condition.setMaterialNo(detailVO.getMaterialsNo());
        List<MaterialLocationRelationVO> voList = materialLocationRelationMapper.list(condition);
        if (!voList.isEmpty()) {
            detailVO.setLocationCode(voList.get(0).getLocationCode());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode update(ReceiptInAddVO receiptInAddVO) throws Exception {
        if (receiptInAddVO.getHeaderInfo() == null || ListUtil.isNullOrEmpty(receiptInAddVO.getDetailList())) {
            return ErrorCode.IllegalArument;
        }
        ReceiptInDO receiptInDO = new ReceiptInDO();
        BeanUtils.copyProperties(receiptInAddVO.getHeaderInfo(), receiptInDO);

        boolean success;
        for (ReceiptInDetailVO detailVO : receiptInAddVO.getDetailList()) {
            ReceiptInDetailDO detailDO = new ReceiptInDetailDO();
            BeanUtils.copyProperties(detailVO, detailDO);
            success = receiptInDetailMapper.update(detailDO) > 0;
            if (!success) {
                throw new Exception("更新运单入库详情记录失败");
            }
        }
        success = receiptInMapper.update(receiptInDO) > 0;
        if (!success) {
            throw new Exception("更新运单入库记录失败");
        }

        //更新出库事务单
        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(receiptInDO.getBillNo(), receiptInDO.getOrgId());
        if (inboundDO == null) {
            throw new Exception("更新失败");
        }
        if (!StringUtils.equals(receiptInDO.getWarehouseCode(), inboundDO.getWarehouseCode())) {
            inboundDO.setWarehouseCode(receiptInDO.getWarehouseCode());
            success = warehouseInboundMapper.updateByPrimaryKeySelective(inboundDO) > 0;
            if (!success) {
                throw new Exception("更新失败");
            }
        }
        return ErrorCode.Success;
    }

    @Transactional(rollbackFor = Exception.class)
    public ErrorCode remove(String id) throws Exception {
        ReceiptInDO receiptInDO = receiptInMapper.selectByPrimaryKey(id);
        if (receiptInDO == null) {
            throw new Exception("参数错误");
        }
        DeliveryReceiptDO deliveryReceiptDO = deliveryReceiptMapper.itemByNo(receiptInDO.getReceiptNo());
        if (deliveryReceiptDO == null) {
            throw new Exception("参数错误");
        }
        List<ReceiptInDetailDO> list = receiptInDetailMapper.listByMainId(id);
        if (ListUtil.isNullOrEmpty(list)) {
            throw new Exception("参数错误");
        }
        if (receiptInDO.getStatus() > 0) {
            throw new Exception("只能删除未入库的入库单");
        }

        for (ReceiptInDetailDO detailDO : list) {
            deliveryReceiptMaterialService.updateSendStatus(deliveryReceiptDO.getId(), receiptInDO.getReceiptNo(), detailDO.getMaterialsNo(), new BigDecimal(-detailDO.getAmount().doubleValue()));
        }
        return receiptInMapper.deleteByPrimaryKey(id) > 0 ? ErrorCode.Success : ErrorCode.Failure;
    }

    public void export(List<String> ids) throws Exception {
        invokeExport(receiptInMapper.findByIds(ids));
    }

    public void exportAll(ReceiptInVO condition) throws Exception {
        Integer count = receiptInMapper.listCount(condition);
        List<ReceiptInDO> dataList = new ArrayList<>();
        int times = count / 500 + 1;
        for (int i = 0; i < times; i++) {
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(receiptInMapper.list(condition));
        }
        invokeExport(dataList);
    }

    private void invokeExport(List<ReceiptInDO> doList) throws Exception {
        String title = "运单入库单数据导出";
        String[] rowsName = new String[]{"序号", "运单入库单号", "发运交接单号", "仓库编码", "入库状态", "制单人", "制单时间",
                "零件编码", "零件名称", "单位", "数量", "入库数量"};
        List<Object[]> dataList = new ArrayList<>();
        Object[] objs;
        for (int i = 0; i < doList.size(); i++) {
            ReceiptInDO exportDO = doList.get(i);
            List<ReceiptInDetailDO> list = receiptInDetailMapper.listByMainId(exportDO.getId());
            for (ReceiptInDetailDO detailDO : list) {
                objs = new Object[rowsName.length];
                objs[0] = i + 1;
                objs[1] = exportDO.getBillNo();
                objs[2] = exportDO.getReceiptNo();
                objs[3] = exportDO.getWarehouseCode();
                objs[4] = getInboundState(exportDO.getStatus());
                objs[5] = exportDO.getCreateName();
                objs[6] = DateUtil.formatDateTime(exportDO.getCreateDate());
                objs[7] = detailDO.getMaterialsNo();
                objs[8] = detailDO.getMaterialsDes();
                objs[9] = detailDO.getUnit();
                objs[10] = detailDO.getAmount();
                objs[11] = detailDO.getRealAmount();
                dataList.add(objs);
            }
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private String getInboundState(Integer state) {
        switch (state) {
            case 0:
                return "未入库";
            case 1:
                return "部分入库";
            case 2:
                return "已入库";
            case 3:
                return "强制结单";
            default:
                return "未入库";
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateByInbound(String billNo, String materialNo, BigDecimal realAmount,
                                   Integer singelState, Integer totalState, String orgId, BarcodeManageDO barcode) throws Exception {
        ReceiptInDO inboundDO = receiptInMapper.findByBillNo(billNo);
        if (inboundDO == null) {
            return false;
        }
        ReceiptInDetailDO detailDO = receiptInDetailMapper.findByMainIdAndMaterialsNo(inboundDO.getId(), materialNo);
        if (detailDO == null) {
            return false;
        }
        detailDO.setRealAmount(realAmount);
        detailDO.setStatus(singelState);
        boolean success = receiptInDetailMapper.update(detailDO) > 0;
        if (success) {
            //更新运单入库单记录
            inboundDO.setStatus(totalState);
            success = receiptInMapper.update(inboundDO) > 0;
            if (!success) {
                return false;
            }
            if (barcode != null) {
                updateReceiptState(barcode, inboundDO.getReceiptNo());
            } else {
                updatePurState(inboundDO.getReceiptNo(), materialNo, realAmount);
            }
        }
        return success;
    }

    public void updatePurState(String receiptNo, String materialNo, BigDecimal realAmount) throws Exception {
        DeliveryReceiptDO deliveryReceiptDO = deliveryReceiptMapper.itemByNo(receiptNo);
        if (deliveryReceiptDO == null) {
            throw new Exception("未找到发运交接单");
        }
        String deliveryReceiptId = deliveryReceiptDO.getId();
        //对比运单入库单该零件的入库数量和对应发运交接单的所有发货通知单中该零件的发货数量总和，
        // 如果两者相等，则适用上游的发货通知单数量中的发货数量回写对应采购订单的入库数量
        //如果不相等，则以下游的入库数量，即realAmount作为入库数量的标准进行回写
        // 这么做是因为上游，即主机厂（售卖方）的发货通知单数量可能跟运单入库单数量不一致，导致逻辑混乱，目前的系统不能支持完美回写入库数量到对应的采购单上，使用此策略可以很大限度避免数据写错
        BigDecimal deliveryQtyTotal = deliveryNoteDetailMapper.getDeliveryQtyByReceiptId(deliveryReceiptDO.getOrgId(), deliveryReceiptId, materialNo);
        deliveryQtyTotal = deliveryQtyTotal == null ? BigDecimal.ZERO : deliveryQtyTotal;
        boolean outAmountStandard = true;
        if (deliveryQtyTotal.compareTo(realAmount) != 0) {
            outAmountStandard = false;
        }
        if (outAmountStandard) {
            receiptiOutAmountStandardWrite(deliveryReceiptDO, materialNo);
        } else {
            receiptiInAmountStandardWrite(deliveryReceiptDO, materialNo, realAmount);
        }
    }


    /**
     * @Des 运单入库按照上游发运数量回写
     * @Date 2021/3/14 17:52
     * @Author wangzhaoyu
     * @Param [deliveryReceiptDO, materialNo, realAmount]
     * @Return void
     */
    public void receiptiOutAmountStandardWrite(DeliveryReceiptDO deliveryReceiptDO, String materialNo) throws Exception {
        String deliveryReceiptId = deliveryReceiptDO.getId();
        List<DeliveryReceiptLinkDO> linkDOS = deliveryReceiptLinkMapper.list(deliveryReceiptId);
        for (DeliveryReceiptLinkDO linkDO : linkDOS) {
            if (linkDO.getDeliveryBillNo() == null) {
                continue;
            }
            if (linkDO.getPurchaseBillNo() == null) {
                continue;
            }
            //获取发运交接单关联单据对应的发货通知单id,然后根据deliveryNoteId+materialsNo查看该发货通知单中是否有当前零件的发货信息
            String deliveryNoteId = linkDO.getDeliveryNoteId();
            DeliveryNoteDetailDO deliveryNoteDetailDO = deliveryNoteDetailMapper.selectByDeliveryNoteIdAndMaterial(deliveryNoteId, materialNo);
            if (deliveryNoteDetailDO == null) {
                continue;
            }
            //发货通知单的发运数量
            BigDecimal deliveryQty = deliveryNoteDetailDO.getDeliveryQty() == null ? BigDecimal.ZERO : deliveryNoteDetailDO.getDeliveryQty();
            DeliveryNoteDO deliveryNote = deliveryNoteMapper.item(deliveryNoteId);
            String purchaseNo = deliveryNote.getPurchaseNo();
            PurchaseRequestDO requestDO = purchaseRequestMapper.itemByBillNo(purchaseNo);
            if (requestDO == null) {
                continue;
            }
            PurchaseRequestDetailDO requestDetailDO = purchaseRequestDetailMapper.findByBillIdAndMaterialNo(requestDO.getBillId(), materialNo, null);
            if (requestDetailDO == null) {
                continue;
            }
            BigDecimal realQty = requestDetailDO.getRealQty();
            BigDecimal needNum = requestDetailDO.getQty().subtract(realQty);
            int compare = needNum.compareTo(deliveryQty);
            if (compare < 0) {
                throw new Exception("入库失败,发货通知单:" + deliveryNote.getDeliveryNo() + ",零件:" + materialNo + "本次发运数量大于剩余需入库量");
            }
            if (compare > 0) {
                requestDetailDO.setStatus(1);
                BigDecimal redNum = realQty.add(deliveryQty);
                requestDetailDO.setRealQty(redNum);
            } else {
                requestDetailDO.setStatus(2);
                BigDecimal redNum = realQty.add(deliveryQty);
                requestDetailDO.setRealQty(redNum);
            }
            boolean success = purchaseRequestDetailMapper.update(requestDetailDO) > 0;
            if (!success) {
                throw new Exception("更新采购申请零件详情失败");
            }
            int status = purchaseRequestDetailMapper.findInBoundStatus(requestDetailDO.getBillId());
            success = purchaseRequestMapper.updateInboundStatus(requestDetailDO.getBillId(), status) > 0;
            if (!success) {
                throw new Exception("更新采购申请入库状态失败");
            }
        }
    }

    /**
     * @Des 运单入库按照入库数量回写
     * @Date 2021/3/14 17:52
     * @Author wangzhaoyu
     * @Param [deliveryReceiptDO, materialNo, realAmount]
     * @Return void
     */
    public void receiptiInAmountStandardWrite(DeliveryReceiptDO deliveryReceiptDO, String materialNo, BigDecimal realAmount) throws Exception {
        String deliveryReceiptId = deliveryReceiptDO.getId();
        List<DeliveryReceiptLinkDO> linkDOS = deliveryReceiptLinkMapper.list(deliveryReceiptId);
        for (DeliveryReceiptLinkDO linkDO : linkDOS) {
            if (realAmount.compareTo(BigDecimal.ZERO) <= 0) {
                return;
            }
            if (linkDO.getDeliveryBillNo() == null) {
                continue;
            }
            if (linkDO.getPurchaseBillNo() == null) {
                continue;
            }
            //获取发运交接单关联单据对应的发货通知单id,然后根据deliveryNoteId+materialsNo查看该发货通知单中是否有当前零件的发货信息
            String deliveryNoteId = linkDO.getDeliveryNoteId();
            DeliveryNoteDetailDO deliveryNoteDetailDO = deliveryNoteDetailMapper.selectByDeliveryNoteIdAndMaterial(deliveryNoteId, materialNo);
            if (deliveryNoteDetailDO == null) {
                continue;
            }
            DeliveryNoteDO deliveryNote = deliveryNoteMapper.item(deliveryNoteId);
            String purchaseNo = deliveryNote.getPurchaseNo();
            PurchaseRequestDO requestDO = purchaseRequestMapper.itemByBillNo(purchaseNo);
            if (requestDO == null) {
                continue;
            }
            PurchaseRequestDetailDO requestDetailDO = purchaseRequestDetailMapper.findByBillIdAndMaterialNo(requestDO.getBillId(), materialNo, null);
            if (requestDetailDO == null) {
                continue;
            }
            BigDecimal needNum = requestDetailDO.getQty().subtract(requestDetailDO.getRealQty());
            int compare = needNum.compareTo(realAmount);
            if (compare > 0) {
                requestDetailDO.setStatus(1);
                BigDecimal redNum = requestDetailDO.getRealQty().add(realAmount);
                requestDetailDO.setRealQty(redNum);
                realAmount = realAmount.subtract(needNum);
            } else if (compare == 0) {
                requestDetailDO.setStatus(2);
                BigDecimal redNum = requestDetailDO.getRealQty().add(realAmount);
                requestDetailDO.setRealQty(redNum);
                realAmount = realAmount.subtract(needNum);
            } else {
                requestDetailDO.setStatus(2);
                realAmount = realAmount.subtract(needNum);
                requestDetailDO.setRealQty(needNum);
            }
            boolean success = purchaseRequestDetailMapper.update(requestDetailDO) > 0;
            if (!success) {
                throw new Exception("更新采购申请零件详情失败");
            }
            int status = purchaseRequestDetailMapper.findInBoundStatus(requestDetailDO.getBillId());
            success = purchaseRequestMapper.updateInboundStatus(requestDetailDO.getBillId(), status) > 0;
            if (!success) {
                throw new Exception("更新采购申请入库状态失败");
            }
        }
    }

    /**
     * @Author: WangKe
     * @Description: 代理商用运单条码入库，回改采购申请单已入库数量和入库状态
     * @Date: 2019/1/28 0028
     */
    public void updateReceiptState(BarcodeManageDO barcode, String receiptNo) throws Exception {
        DeliveryReceiptDO deliveryReceiptDO = deliveryReceiptMapper.itemByNo(receiptNo);
        if (deliveryReceiptDO == null) {
            throw new Exception("未找到发运交接单");
        }
        String orgId = deliveryReceiptDO.getOrgId();
        if (!StringUtils.equals(deliveryReceiptDO.getBillType(), BillDesc.DeliveryNo.getDesc())) {
            //只改发货通知单
            return;
        }
        PageHelperPlus.orderBy("create_date desc");
        //根据条码+发运交接单关联的业务出库单据查找条码出库记录
        List<WarehouseDeliveryRecordDO> recordDOList = warehouseDeliveryRecordMapper.selectDeliveryRecordsByReceiptNo(barcode.getBarcode(), orgId, receiptNo);
        if (ListUtil.isNullOrEmpty(recordDOList)) {
            throw new Exception("未根据条码找到出库记录");
        }
        for (WarehouseDeliveryRecordDO recoredDo : recordDOList
        ) {
            DeliveryNoteDO deliveryNoteDO = deliveryNoteMapper.itemByNo(recoredDo.getBusinessOrder(), orgId);
            if (deliveryNoteDO == null) {
                throw new Exception("未根据条码找到发货通知单");
            }
            SaleIntentionDO saleIntentionDO = saleIntentionMapper.itemByNo(deliveryNoteDO.getSaleNo(), orgId);
            if (saleIntentionDO == null) {
                throw new Exception("未根据条码找到销售意向单");
            }
            PurchaseRequestDO requestDO = purchaseRequestMapper.itemByPurchase(saleIntentionDO.getPurchaseNo(), saleIntentionDO.getPurchaseOrgId());
            if (requestDO == null) {
                continue;
                //throw new Exception("未根据条码找到采购申请单");
            }
            PurchaseRequestDetailDO requestDetailDO = purchaseRequestDetailMapper.findByBillIdAndMaterialNo(requestDO.getBillId(), recoredDo.getMaterialNo(), null);
            if (requestDetailDO == null) {
                throw new Exception("未根据条码找到采购申请零件详情");
            }
            BigDecimal sum = requestDetailDO.getRealQty().add(recoredDo.getAmount());
            int compare = sum.compareTo(requestDetailDO.getQty());
            if (compare > 0) {
                throw new Exception("入库数量大于采购申请详情最大数量，采购单：" + requestDO.getBillNo() + "，零件：" + requestDetailDO.getMaterialsNo());
            } else if (compare == 0) {
                requestDetailDO.setStatus(2);
            } else {
                requestDetailDO.setStatus(1);
            }
            requestDetailDO.setRealQty(sum);
            boolean success = purchaseRequestDetailMapper.update(requestDetailDO) > 0;
            if (!success) {
                throw new Exception("更新采购申请零件详情失败");
            }

            int status = purchaseRequestDetailMapper.findInBoundStatus(requestDetailDO.getBillId());
            success = purchaseRequestMapper.updateInboundStatus(requestDetailDO.getBillId(), status) > 0;
            if (!success) {
                throw new Exception("更新采购申请入库状态失败");
            }
        }

    }

    public BigDecimal getPrice(String billNo, String materialNo) throws Exception {
        ReceiptInDO inboundDO = receiptInMapper.findByBillNo(billNo);
        if (inboundDO == null) {
            return null;
        }
        DeliveryReceiptDO deliveryReceiptDO = deliveryReceiptMapper.itemByNo(inboundDO.getReceiptNo());
        if (deliveryReceiptDO == null) {
            return null;
        }

        List<DeliveryReceiptLinkDO> deliveryReceiptLinkDOList = deliveryReceiptLinkMapper.list(deliveryReceiptDO.getId());
        if (deliveryReceiptLinkDOList == null || deliveryReceiptLinkDOList.size() <= 0) {
            return null;
        }

        BoxupMaterialsQuery boxupMaterialsQuery = new BoxupMaterialsQuery();
        boxupMaterialsQuery.setDeliveryReceiptLinkDOList(deliveryReceiptLinkDOList);
        boxupMaterialsQuery.setBillId(deliveryReceiptDO.getId());
        boxupMaterialsQuery.setMaterialsNo(materialNo);
        return boxupDetailMapper.getUnitPriceAfterAdjust(boxupMaterialsQuery);
    }

    /**
     * 手动完成单据<br>
     * materialsNo 不为null,则更改该单据下的零件状态为“手动完成”状态；如果materialsNo为空，则更改整个单据为“手动完成”状态
     *
     * @param billNo      String 单据编号
     * @param materialsNo String 零件编号
     * @param orgId       String 企业ID
     * @return Er11rorCode 返回码
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String billNo, String materialsNo, String orgId) throws Exception {
        ReceiptInDO receiptInDO = receiptInMapper.findByBillNo(billNo);
        if (receiptInDO == null) {
            return ErrorCode.IllegalArument;
        }

        if (StringUtil.isNullOrEmpty(materialsNo)) { //零件编码为空，更新单据状态为“手动完成”
            receiptInMapper.updateStatus(billNo, 3, orgId);
            warehouseInboundService.updateState(billNo, 3, orgId);

            receiptInDetailMapper.updateStatus(receiptInDO.getId(), null, 3);
            warehouseInboundDetailMapper.updateAllStatus(3, billNo, orgId);
        } else {
            receiptInDetailMapper.updateStatus(receiptInDO.getId(), materialsNo, 3);
            warehouseInboundService.updateDetailState(billNo, materialsNo, null, 3, orgId);
            ErrorCode errorCode = checkBillFinished(receiptInDO.getId(), receiptInDO.getBillNo(), orgId);

            if (ErrorCode.Success != errorCode) {
                return errorCode;
            }
        }

        //如果是由发运交接单生成，更新发运交接单状态
        if (!StringUtil.isNullOrEmpty(receiptInDO.getReceiptNo())) {
            List<ReceiptInDetailDO> detailDOList = receiptInDetailMapper.findListByMainIdAndMaterialsNo(receiptInDO.getId(), materialsNo);
            for (ReceiptInDetailDO detailDO : detailDOList) {
                deliveryReceiptMaterialService.manualUpdateSendStatus(receiptInDO.getReceiptNo(), detailDO.getMaterialsNo(),
                        CalcUtil.subtract(BigDecimal.ZERO, (detailDO.getAmount().subtract(detailDO.getRealAmount() == null ? BigDecimal.ZERO : detailDO.getRealAmount()))));
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 校验单据是否已完成<br>
     * 判断单据下的所有零件是否已经完成，如果都完成，则更改单据状态为完成
     *
     * @param billNo String
     * @param orgId  String
     * @return Boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode checkBillFinished(String billId, String billNo, String orgId) throws Exception {
        List<ReceiptInDetailDO> detailDOList = receiptInDetailMapper.listByMainId(billId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            throw new Exception("未查询到运单入库单详情列表");
        }
        boolean manul = false;
        boolean flag = true;
        int status;
        for (ReceiptInDetailDO temp : detailDOList) {
            if (3 == temp.getStatus()) {
                manul = true;
            }
            if (2 == temp.getStatus() || 3 == temp.getStatus()) {
                //完成状态
                continue;
            }
            flag = false;
        }
        if (flag) {
            if (manul) {
                status = 3;
            } else {
                status = 2;
            }
        } else {
            status = 1;
        }
        receiptInMapper.updateStatus(billNo, status, orgId);
        warehouseInboundService.updateState(billNo, status, orgId);
        return ErrorCode.Success;
    }
}
